package Context
{
    import Page.Page;
    import Page.PageSet;
    
    import Regex.Regex;
    import Regex.RegexFile;
    
    import flash.events.Event;
    import flash.filesystem.File;
    import flash.filesystem.FileMode;
    import flash.filesystem.FileStream;
    import flash.geom.Rectangle;
    import flash.text.Font;
    
    import mx.collections.ArrayCollection;
    import mx.controls.Alert;
    
    [Event(name=Event.CHANGE, type="flash.events.Event")]
//    [Event(name=ListEvent.CHANGE, type="flash.events.ListEvent")]
    
    [Bindable]
    public class Context
    {
        public const LETTERS_WITH_ACCENTS:String = "ÀÁÂÃÄÅàáâãäåÇçÈÉÊËèéêëÌÍÎÏìíîïÒÓÔÕÖØòóôõöøÑñÙÚÛÜùúûüÝÿý";
        private static const DEFAULT_REGEX_FILE_NAME:String = "Twister.regex";
        private static const TWISTER_CONFIG_FILE_NAME:String = "Twister.cfg";
        
        public const WORD_EXTENDED_REGEX:RegExp = /[\wÀÁÂÃÄÅàáâãäåÇçÈÉÊËèéêëÌÍÎÏìíîïÒÓÔÕÖØòóôõöøÑñÙÚÛÜùúûüÝÿý]+/;
        public const WORD_EXTENDED_PLUS_HYPHEN_REGEX:RegExp = /[\wÀÁÂÃÄÅàáâãäåÇçÈÉÊËèéêëÌÍÎÏìíîïÒÓÔÕÖØòóôõöøÑñÙÚÛÜùúûüÝÿý-]+/;
        public const WORDS_EXTENDED_REGEX:RegExp = /([^\wÀÁÂÃÄÅàáâãäåÇçÈÉÊËèéêëÌÍÎÏìíîïÒÓÔÕÖØòóôõöøÑñÙÚÛÜùúûüÝÿý]*)([\wÀÁÂÃÄÅàáâãäåÇçÈÉÊËèéêëÌÍÎÏìíîïÒÓÔÕÖØòóôõöøÑñÙÚÛÜùúûüÝÿý]+)([^\wÀÁÂÃÄÅàáâãäåÇçÈÉÊËèéêëÌÍÎÏìíîïÒÓÔÕÖØòóôõöøÑñÙÚÛÜùúûüÝÿý]*)/g;
        private static const QUOTES_REGEX_SOURCE:RegExp = /([^\s\(-]?)"(\s*)([^\\]*?(\\.[^\\]*)*)(\s*)("|^\r)([^\s\)\.\,;:-]?)/img;
    
        private static const REGEX_MODE:Number = 0;
        private static const QUOTES_MODE:Number = 1;
    
        private var _mode:Number = REGEX_MODE;
        private var _page_set:PageSet;
        private var _activeFolder:File;
        private var _active_page:Page;
//        private var _active_page_index:int;
        private var _active_regex_file:RegexFile;
        private var _rectangle:Rectangle;
//        private var _charset:String = "iso-8859-1";
        private var _charset:String = "utf-8";
        private var _versionString:String;
        private var _fontSize:Number = 18;
//        private var _fontFamily:String = "_typewriter";
        private var _fontFamily:String = "DejaVu Sans Mono";
//        private var _regex_list_index:Number = 0;
//        private var _active_regex_index:int = -1;
        private var _active_regex:Regex;
        private var _quotes_regex:Regex;
        private var _is_quotes_regex:Regex;
                
        public function Context()
        {
            this._quotes_regex = new Regex(QUOTES_REGEX_SOURCE);
        }
        
        private function get DefaultDirectory():String {
        	return File.applicationDirectory.nativePath;
        }
        
        public function get FontFamily():String {
            return _fontFamily;
        }
        
        public function set FontFamily(s:String):void {
            _fontFamily = s;
        }
        
        public function get FontSize():Number {
            return _fontSize;
        }

        public function set FontSize(n:Number):void {
            _fontSize = n;
        }        
        
        public function get Charset():String {
            return _charset;
        }
        
        public function set Charset(cset:String):void {
            _charset = cset;
        }
        
        private function get versionString():String {
            return _versionString;
        }
        
        private function set versionString(s:String):void {
            _versionString = s;
        }
 
        public function get ActiveRegexIndex():Number {
//        	trace("get regex index ", this.Regexes.getItemIndex(_active_regex));
        	return this.Regexes.getItemIndex(_active_regex);
        }
        
        public function set ActiveRegexIndex(i:Number):void {
//        	trace("set regex index ", i);
            ActiveRegex = _active_regex_file.Regexes.getItemAt(i) as Regex;
        }
        
        public function set ActiveRegex(r:Regex):void {
            _active_regex = r;
        }
        
        private function get Regexes():ArrayCollection {
        	return this.ActiveRegexFile.Regexes;
        }
//        
//        private function set Regexes(ac:ArrayCollection):void {
//        	
//        }
        public function SetRegexMode():void {
            _mode = REGEX_MODE;            
        }
        
        public function SetQuotesMode():void {
            _mode = QUOTES_MODE;
        }
        
        public function get QuotesRegex():Regex {
            return this._quotes_regex;
        }

        public function get IsQuotesMode():Boolean {
            return _mode == QUOTES_MODE;
        }
        
        public function get ActiveRegex():Regex {
        	return _active_regex;
        }
        
        public function BrowseForRegexFile():void {
        	ActiveRegexFile.addEventListener(Event.SELECT, eRegexFileSelected, false, 0, true);
        	ActiveRegexFile.browseForOpen("Regular expression source file (*.regex)", "regex" as Array);
        }
        
        public function get RegexFilePath():String {
        	return ActiveRegexFile.nativePath;	
        }
        
	    private function eRegexFileSelected(e:Event):void {
	        if(e.target !== null) {
	            var f:File = e.target as File;
	            if(f.exists) {
	                setActiveRegexFile(e.target as File);
//	                this.tblRegexes.dataProvider = gContext.ActiveRegexFile.Regexes;
//	                this.lblRegexPath.text = gContext.ActiveRegexFile.nativePath;
	            }    
	        }    
	    }
		
		public function getRegexByIndex(i:int):Regex {
            return ActiveRegexFile.Regexes.getItemAt(i) as Regex;
		}
		
//		public function get ActiveRegexPatternString():String {
//			return ActiveRegex.PatternString;
//		}
//		
//		public function set ActiveRegexPatternString(s:String):void {
//			ActiveRegex.PatternString = s;
//		}

//		public function get ActiveRegexReplacePattern():String {
//			return ActiveRegex.ReplacePattern;
//		}
//		
//		public function set ActiveRegexReplacePattern(s:String):void {
//			ActiveRegex.ReplacePattern = s;
//		}
//		
		
        public function getTextInstances( regex:RegExp ): ArrayCollection {
            var a:Array = this.Pages.getTextInstances( regex );   
            var ret:ArrayCollection = new ArrayCollection( a );
            return ret; 
        }
        
//        public function setPage(index:int):void {
//            ActivePage = getPage(index);
//        }
        
        public function getPage(index:int):Page {
            return Pages.getPage(index);    
        }
        
        public function MatchCount(re:Regex):Number {
            var n:Number = 0;
            if( ! re) {
                return 0;
            }
            
            return this.Pages.MatchCount(re);
//            for each(var p:Page in this.Pages) {
//                n += p.MatchCount(re);
//            }
//            return n;
        }
        
        public function get MatchQuotesCount():Number {
        	return MatchCount(QuotesRegex);
        }
        
        public function get IsActiveRegex():Boolean {
        	return ! ( ActiveRegex == null );	
        }
        
        public function get IsActiveRegexFile():Boolean {
        	return _active_regex_file && _active_regex_file.exists;
        }
        
        private function setActiveRegexFile(pFile:File):void {
            ActiveRegexFile = new RegexFile(pFile.nativePath);
            ActiveRegexIndex = 0;
        }

		public function get IsDotAll():Boolean {
			return ActiveRegex.dotall;
		}
		
		public function get IsIgnoreCase():Boolean {
			return ActiveRegex.ignorecase;
		}
		
		public function get IsMultiLine():Boolean {
			return ActiveRegex.multiline;
		}
		
		public function get IsUnAccent():Boolean {
			return ActiveRegex.unaccent;
		}
		
		public function set IsDotAll(_is:Boolean):void {
			ActiveRegex.dotall = _is;
		}
		
		public function set IsIgnoreCase(_is:Boolean):void {
			ActiveRegex.ignorecase = _is;
		}
		
		public function set IsMultiLine(_is:Boolean):void {
			ActiveRegex.multiline = _is;
		}
		
		public function set IsUnAccent(_is:Boolean):void {
			ActiveRegex.unaccent = _is;
		}
		
        public function set rectangle(rect:Rectangle):void {
            _rectangle = rect;    
        }
        
        public function get rectangle():Rectangle {
            return _rectangle;
        }
        
        public function getRegexAt(i:Number):Regex {
            return _active_regex_file.Regexes.getItemAt(i) as Regex;
        }
        
       public function serialize():void {
            var o:Object = new Object;
            
            if(ActiveFolder) {
                o.activeFolderPath = ActiveFolder.nativePath;
            }
            if(ActiveRegexFile) {
                o.ActiveRegexPath = ActiveRegexFile.nativePath;
            }
            
            if(_rectangle) {
                o.rectangle = _rectangle;
            }
            if(_charset.length > 0) {
                o.charset = _charset;
            }
            
            if(_versionString && _versionString.length > 0) {
                o.versionString = _versionString;
            }
            
            o.fontSize = _fontSize;
            o.fontFamily =  _fontFamily;

            var s:FileStream    = new FileStream();
            s.open(contextFile, FileMode.WRITE);
            s.writeObject(o);
            s.close()
        }
    
    
//        public function Fix1252():void {
//            var re:Regex = new Regex("ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•--˜™š›œžŸ", "gm", "", "1252 80-9F");
//            var o:Object;
//            for each(var pg:Page in this._page_set) {
//                o = re.RegExpExec(pg.text);
//                while(o && o.index > 0) {
//                    pg.text = pg.text.replace(/ƒ/, "f");
//                    pg.text = pg.text.replace(/„/, '"');
//                    pg.text = pg.text.replace(/…/, "...");
//                    pg.text = pg.text.replace(/†/, "*");
//                    pg.text = pg.text.replace(/‡/, "**");
//                    pg.text = pg.text.replace(/ˆ/, "^");
//                    pg.text = pg.text.replace(/‰/, "[0/00]");
//                    pg.text = pg.text.replace(/Š/, "S");
//                    pg.text = pg.text.replace(/‹/, "'");
//                    pg.text = pg.text.replace(/Ž/, "Z");
//                    pg.text = pg.text.replace(/‘/, "'");
//                    pg.text = pg.text.replace(/’/, "'");
//                    pg.text = pg.text.replace(/“/, "'");
//                    pg.text = pg.text.replace(/”/, '"');
//                    pg.text = pg.text.replace(/•/, "*");
//                    pg.text = pg.text.replace(/˜/, "~");
//                    pg.text = pg.text.replace(/™/, "[TM]");
//                    pg.text = pg.text.replace(/š/, "s");
//                    pg.text = pg.text.replace(/›/, "'");
//                    pg.text = pg.text.replace(/œ/, "[oe]");
//                    pg.text = pg.text.replace(/ž/, "z");
//                }
//            }
//        "\x{80}" => "\x{20AC}",
//        "\x{82}" => "\x{201A}",
//        "\x{83}" => "\x{0192}",
//        "\x{84}" => "\x{201E}",
//        "\x{85}" => "\x{2026}",
//        "\x{86}" => "\x{2020}",
//        "\x{87}" => "\x{2021}",
//        "\x{88}" => "\x{02C6}",
//        "\x{89}" => "\x{2030}",
//        "\x{8A}" => "\x{0160}",
//        "\x{8B}" => "\x{2039}",
//        "\x{8C}" => "\x{0152}",
//        "\x{8E}" => "\x{017D}",
//        "\x{91}" => "\x{2018}",
//        "\x{92}" => "\x{2019}",
//        "\x{93}" => "\x{201C}",
//        "\x{94}" => "\x{201D}",
//        "\x{95}" => "\x{2022}",
//        "\x{96}" => "\x{2013}",
//        "\x{97}" => "\x{2014}",
//        "\x{98}" => "\x{02DC}",
//        "\x{99}" => "\x{2122}",
//        "\x{9A}" => "\x{0161}",
//        "\x{9B}" => "\x{203A}",
//        "\x{9C}" => "\x{0153}",
//        "\x{9E}" => "\x{017E}",
//        "\x{9F}" => "\x{0178}"
//        }
    
        public function unserialize():void {
            _activeFolder = File.applicationDirectory;
            if(! contextFile.exists) {
                virginize();
                return;
            }
            var s:FileStream = new FileStream();
            s.open(contextFile, FileMode.READ);
            var o:Object = s.readObject();
            s.close();
            if(o.fontSize && parseInt(o.fontSize, 10) > 0) {
                _fontSize = o.fontSize;
            }
            if(o.fontFamily && o.fontFamily.length > 0) {
                _fontFamily = o.fontFamily.toString();
            }
            if(o.charset && o.charset.length > 0) {
                _charset = o.charset;
            }
            
            if(o.versionString && o.versionString.length > 0) {
                _versionString = o.versionString;
            }
            
            if(o.activeFolderPath && o.activeFolderPath.length > 0) {
                var afolder:File = ActiveFolder.resolvePath(o.activeFolderPath);
                if(afolder.exists && afolder.isDirectory) {
                    ActiveFolder = afolder;
                }                   
            }
            
            if(o.ActiveRegexPath && o.ActiveRegexPath.length > 0) {
                this._active_regex_file = new RegexFile(o.ActiveRegexPath);
            }
            else {
            	this._active_regex_file = new RegexFile( File.applicationDirectory.nativePath + "/" + DEFAULT_REGEX_FILE_NAME);
            }
            
            if(o.rectangle) {
                _rectangle = o.rectangle as Rectangle;
            }
        }

        private function get contextFile():File {
            var f:File = File.applicationStorageDirectory.resolvePath(TWISTER_CONFIG_FILE_NAME);
//            trace("context file: ", f.nativePath);
            return f;
        }

        public function get ActiveRegexFile():RegexFile {
            return _active_regex_file;
        }   
        
        private function set ActiveRegexFile(rf:RegexFile):void {
        	_active_regex_file = rf;
        }
        
        public function get ActiveRegexPath():String {
        	return _active_regex_file.nativePath;
        }     
        
        public function set ActiveRegexPath(s:String):void {
        	
        }

        public function get ActivePage():Page {
//        	return getPage( _active_page_index );
            return _active_page;
        }
        
        private function set ActivePage(p:Page):void {
        	_active_page = p;	
        }
        
        public function get FirstPage():Page {
            if(Pages.length > 0){
                return Pages.FirstPage;
            } else {
                return null;
            }
        }
        
        public function getNextPage(pg:Page):Page {
            var i:int = Pages.getPageIndex(pg);
            if(i < Pages.length - 1) {
                return Pages.getPage(i+1) as Page;
            } else {
                return null;
            }
        }

        public function get ActiveFolder():File {
            return _activeFolder;
        }
        
         private function set ActiveFolder(pFolder:File):void {
             var f:File;
             if( ( _activeFolder === pFolder ) && _page_set ) {
                 return;
             }
             if(! pFolder.isDirectory) {
                Alert.show("Setting ActiveFolder to on-directory <" + pFolder.nativePath + ">");
             }
             if(_page_set) {
                 _page_set.saveMap();
                 _page_set = null;
             }
             
            _activeFolder = pFolder;
            
            Pages = new PageSet(pFolder, _charset);
//            Pages.InitText();
            setFirstPageActive();
        }
        
        public function get Pages():PageSet {
            return _page_set;
        }
        
        private function set Pages(ifs:PageSet):void {
            _page_set = ifs;
        }
        
        public function get PageCount():int {
            if(_page_set) {
                return _page_set.length;
            }
            else
            {
                return 0;
            }
        }
        
//        public function get ActivePageName():String {
//        	return ActivePage.PageName;
//        }
//        
//        public function set ActivePageText(s:String):void {
//        	ActivePage.Text = s;
//        }
//        
//        public function get ActivePageText():String {
//        	return ActivePage.Text;
//        }
        
//        public function get ActivePageHtmlText():String {
//        	return ActivePage.HtmlText;
//        }
        
//        public function get ActivePageImageUrl():String {
//        	return ActivePage.ImageUrl;
//        }
//        
//        public function get ActivePageIndex():int {
//        	return ActivePage.index;
//        }
//        
		private function set_active_page(p:Page):void {
        	ActivePage = p;
//        	trace("dispatch", p.index);
        	dispatchEvent( new Event(Event.CHANGE, true, true));
		}
        public function SetActivePageIndex(i:int):void {
        	set_active_page(getPage(i));
        }
        
//        private function set ActivePage(fi:Page):void {
//            if(_active_page === fi) {
//                return;
//            }
//            if(fi !== null) {
//                _active_page = fi;
//            } else {
//                _active_page = null;
//            }
//            
//        }
        
//        public function get ActivePageWrappedText():String {
//        	return ActivePage.WrappedText;
//        }
//        
//        public function ActivePageReplaceAll(re:Regex):void {
//        	ActivePage.ReplaceAll(re);
//        }
//        
//        public function ActivePageMatchCount(re:Regex):int {
//        	return ActivePage.MatchCount(re);
//        }
        
//        public function get ActivePageMatchQuotesCount():int {
//        	return ActivePage.MatchQuotesCount;
//        }
//        
        public function setFirstPageActive():void {
            if( _page_set && _page_set.length ) {
            	set_active_page(getPage(0));
            }
            else {
                set_active_page(null);
            }
        }
        
        public function get ActivePageIndex():int {
        	if(! ActivePage ) {
        		return -1;
        	}
        	else {
        		return ActivePage.index;
        	}
        }
        
        public function set ActivePageIndex(i:int):void {
        	this.SetActivePageIndex(i);
        }
        
        public function get IsActivePage():Boolean {
        	return _active_page != null;
//        	return( ( Pages != null ) && _active_page_index >= 0 );
        }
        
        public function setLastPageActive():void {
            if( this._page_set && _page_set.length ) {
            	set_active_page( _page_set.LastPage );
            }
            else {
                set_active_page(null);
            }
//            else {
//            	ActivePageIndex = -1;
////                ActivePage = null;
//            }
        }

        public function IncrementActivePage():void {
        	if(! IsActivePage ) {
        		return;
        	}
        	var i:int = _active_page.index;
        	if(i < _page_set.length - 1 ) {
                set_active_page( getPage(i + 1) );
        	} 
//            if(!ActivePage) {
//                return;
//            }
//            var i:int = ActivePage.index;
//            if(i < Pages.length-1) {
//                ActivePage = Pages.getPage(i+1) as Page;
//            }   
//            else {
//                this.setFirstPageActive();
//            }
        }    

        public function DecrementActivePage():void {
            if(! IsActivePage) {
                return;
            }
            var i:int = ActivePage.index;
            if(_active_page.index > 0) {
                set_active_page( getPage(i - 1) );
            }
        }    

        public function virginize():void {
            if(contextFile.exists) {
                contextFile.deleteFile();
            }
            ActiveFolder = File.applicationDirectory;
            serialize();
        }
        public function get Fonts():Array {
            import flash.text.Font; 
            return Font.enumerateFonts(true).sortOn("fontName", Array.CASEINSENSITIVE);
//            allFonts.sortOn("fontName", Array.CASEINSENSITIVE);
        }
        public function get FontNames():ArrayCollection {
            var a:Array = new Array(); 
            for each(var f:Font in Fonts) {
                a.push(f.fontName);
            }
            return new ArrayCollection(a);
        }
        
        public function set FontNames(ac:ArrayCollection):void {}
    }
}